/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.web.gwt.form.client.manager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import com.genia.toolbox.web.gwt.basics.client.i18n.GwtI18nMessage;
import com.genia.toolbox.web.gwt.form.client.validator.ValidatorCallback;
import com.genia.toolbox.web.gwt.form.client.widget.item.ComplexItemWidget;
import com.genia.toolbox.web.gwt.form.client.widget.item.ItemWidget;
import com.genia.toolbox.web.gwt.form.client.widget.item.SimpleItemWidget;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;

/**
 * Class used to validate all the data of a form. It uses callback to insure
 * that all validation are made before sending a result.
 */
public class FormValidatorCommand
    implements Command
{

  /**
   * the entryIterator that traverse all widgets.
   */
  private transient Iterator<Entry<String, SimpleItemWidget>> simpleItemEntryIterator = null;

  /**
   * the entryIterator that traverse all widgets.
   */
  private transient Iterator<Entry<String, ComplexItemWidget>> complexItemEntryIterator = null;

  /**
   * the formIterator that traverse all {@link FormManager}.
   */
  private transient Iterator<FormManager> formManagerIterator;

  /**
   * the callback once all validation is done.
   */
  private transient ValidatorCallback callback;

  /**
   * the current list of errors.
   */
  private transient final List<GwtI18nMessage> errors = new ArrayList<GwtI18nMessage>();



  /**
   * constructor.
   * 
   * @param formManager
   *          the {@link FormManager} to validate
   * @param callback
   *          the callback once all validation is done
   */
  public FormValidatorCommand(FormManager formManager, final ValidatorCallback callback)
  {
    List<FormManager> formManagers = new ArrayList<FormManager>();
    formManagers.add(formManager);
    init(formManagers, callback);
  }



  /**
   * constructor.
   * 
   * @param formManagers
   *          the {@link FormManager}s to validate
   * @param callback
   *          the callback once all validation is done
   */
  public FormValidatorCommand(final Collection<FormManager> formManagers, final ValidatorCallback callback)
  {
    init(formManagers, callback);
  }



  /**
   * initialisation method.
   * 
   * @param formManagers
   *          the {@link FormManager}s to validate
   * @param callback
   *          the callback once all validation is done
   */
  private void init(final Collection<FormManager> formManagers, final ValidatorCallback callback)
  {
    this.formManagerIterator = new ArrayList<FormManager>(formManagers).iterator();
    this.callback = callback;
  }



  /**
   * retuns the next {@link ItemWidget} to check.
   * 
   * @return the next {@link ItemWidget} to check
   */
  private Entry<String, ? extends ItemWidget> getNextEntry()
  {
    while ((simpleItemEntryIterator == null || !simpleItemEntryIterator.hasNext()) && (complexItemEntryIterator == null || !complexItemEntryIterator.hasNext()) && formManagerIterator.hasNext()) {
      FormManager nextFormManager = formManagerIterator.next();
      simpleItemEntryIterator = new HashMap<String, SimpleItemWidget>(nextFormManager.getSimpleItemWidgets()).entrySet().iterator();
      complexItemEntryIterator = new HashMap<String, ComplexItemWidget>(nextFormManager.getComplexItemWidgets()).entrySet().iterator();
    }
    if (simpleItemEntryIterator != null && simpleItemEntryIterator.hasNext()) {
      return simpleItemEntryIterator.next();
    }
    if (complexItemEntryIterator != null && complexItemEntryIterator.hasNext()) {
      return complexItemEntryIterator.next();
    }
    return null;
  }



  /**
   * the execute method.
   */
  public void execute()
  {
    final Entry<String, ? extends ItemWidget> entry = getNextEntry();
    if (entry != null) {
      final ItemWidget itemWidget = entry.getValue();
      // We must validate the current formValue
      itemWidget.validate(new ValidatorCallback()
      {
        public void validationResult(final List<GwtI18nMessage> result)
        {
          if (result != null) {
            errors.addAll(result);
          }
          DeferredCommand.addCommand(FormValidatorCommand.this);
        }
      });
    }
    else {
      callback.validationResult(errors);
    }
  }
}
